import os
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, QLocale
from PyQt5.Qt import QDesktopWidget, QShortcut, QFont, QFrame, QAction, QSyntaxHighlighter, QTextCharFormat, QRegExp, \
    QDateTime, QCursor, QIcon, QPixmap, QWidget, QDialog

from ..ui_utils import kill_proc_tree
from ..widgets.QSwitch import QSwitch
from PyQt5.Qt import QIcon
from ui.base._config import UI_RES_PATH

__all__ = ['BaseWindow']


class BaseWindow:
    def __init__(self):
        self.observer_list = []
        self.__initUI()
        self.__connect()

        self._initUI()  # 子页面UI
        self._connect()  # 子页面信号绑定
        self.SetWindowCentered()

    def __initUI(self):
        font = QFont()
        font.setFamily('Microsoft YaHei')
        font.setPointSize(12)
        self.window_icon = QIcon(str(UI_RES_PATH / 'logo.png'))
        self.setWindowIcon(self.window_icon)
        self.setFont(font)

    def __connect(self):
        QShortcut('Ctrl+C', self).activated.connect(lambda: kill_proc_tree(os.getpid(), True))

    def SetWindowCentered(self, flag=True):
        """ 窗体居中 """
        if flag:
            screen = QDesktopWidget().screenGeometry()
            size = self.geometry()
            self.move((screen.width() - size.width()) / 2,
                      (screen.height() - size.height()) / 2)
        else:
            pass

    def SetWindowLocks(self, flag=True):
        """ 锁定/置顶窗口 """
        if flag:
            # self.setWindowFlags(Qt.WindowStaysOnTopHint)
            self.setWindowModality(Qt.ApplicationModal)
        else:
            pass

    def QInfoItem(self, var, txt, value, parent, style='', alignment=Qt.AlignCenter, font=None):
        """ 信息栏条目 """
        splitter_obj = self.QSplitterPack(var, parent, Qt.Horizontal)
        label_name = f"label_{var.lower()}"
        label_obj = QtWidgets.QLabel(txt, parent)
        setattr(self, label_name, label_obj)
        label_obj.setFont(font) if font else None
        if isinstance(value, str):
            value_name = f'{var.upper()}'
            value_obj = QtWidgets.QLabel(value, parent)
            setattr(self, value_name, value_obj)
            value_obj.setStyleSheet(style)
            value_obj.setFont(font) if font else None
            value_obj.setAlignment(alignment)
        else:
            value_obj = value
        splitter_obj.addWidget(label_obj)
        splitter_obj.addWidget(value_obj)
        splitter_obj.setStretchFactor(1, 1)
        return splitter_obj

    def QSplitterBand(self, *args, var, parent, orientation=Qt.Horizontal):
        splitter_obj = self.QSplitterPack(var, parent, orientation)
        _ = [splitter_obj.addWidget(item) for item in args]
        return splitter_obj

    def QLayoutBand(self, *args, var, orientation):
        layout_name = 'layout_%s' % var
        orientation = orientation.lower()
        if orientation == 'h':
            setattr(self, layout_name, QtWidgets.QHBoxLayout())
        elif orientation == 'v':
            setattr(self, layout_name, QtWidgets.QVBoxLayout())
        layout_obj: QtWidgets.QHBoxLayout = getattr(self, layout_name)
        for item, stretch in args:
            if isinstance(item, (QtWidgets.QHBoxLayout, QtWidgets.QVBoxLayout)):
                layout_obj.addLayout(item, stretch)
            else:
                layout_obj.addWidget(item, stretch)
        return layout_obj

    def QDockBand(self, var, title, w, h, p):
        """
        创建一个停靠栏，并将其添加到主窗口中。

        参数:
        - var: 停靠栏的变量名后缀，用于生成唯一的停靠栏名称和内容名称。
        - title: 停靠栏的标题，将设置为窗口标题。
        - w: 停靠栏的固定宽度，如果提供的话。
        - h: 停靠栏的固定高度，如果提供的话。
        - p: 停靠栏的位置，用于确定停靠栏在主窗口中的位置。

        返回值: 无
        """
        # 生成停靠栏的名称，并创建停靠栏对象
        dock_name = f'dock_{var}'
        setattr(self, dock_name, QtWidgets.QDockWidget(self))
        dock_obj: QtWidgets.QDockWidget = getattr(self, dock_name)

        # 设置停靠栏的标题
        dock_obj.setWindowTitle(title)

        # 如果提供了宽度和高度，则设置停靠栏的固定尺寸
        if w:
            dock_obj.setFixedWidth(w)
        if h:
            dock_obj.setFixedHeight(h)

        # 生成停靠栏内容的名称，并创建内容 widget
        content_name = f'dock_content_{var}'
        setattr(self, content_name, QtWidgets.QWidget())
        content_obj: QtWidgets.QWidget = getattr(self, content_name)

        # 创建一个网格布局，并将其应用于内容 widget
        grid_name = f'grid_dock_{var}'
        setattr(self, grid_name, QtWidgets.QGridLayout(content_obj))
        grid_obj: QtWidgets.QGridLayout = getattr(self, grid_name)

        # 自定义方法，用于填充停靠栏的内容
        self._dockContent(var, content_obj, grid_obj)

        # 将内容 widget 设置为停靠栏的子 widget
        dock_obj.setWidget(content_obj)

        # 将停靠栏添加到主窗口指定的位置
        self.addDockWidget(p, dock_obj)

    def QSplitterPack(self, var, parent, orientation=Qt.Horizontal):
        splitter_name = f'splitter_{var}'
        # print(f"QSplitterPack: {splitter_name}")
        setattr(self, splitter_name, QtWidgets.QSplitter(orientation, parent))
        splitter_obj: QtWidgets.QSplitter = getattr(self, splitter_name)
        splitter_obj.setChildrenCollapsible(False)
        splitter_obj.setHandleWidth(0)
        return splitter_obj

    def QActionPack(self, var, text, obj, icon_path=None):
        name = 'action_' + var
        setattr(self, name, QAction(self))
        action_obj: QAction = getattr(self, name)
        action_obj.setCheckable(False)
        if icon_path:
            icon = QIcon()
            icon.addPixmap(QPixmap(icon_path))
            action_obj.setIcon(icon)
        font = QFont()
        font.setPointSize(15)
        action_obj.setFont(font)
        action_obj.setText(text)
        obj.addAction(action_obj)

    def QDateTimePack(self, var, parent):
        name = '%s' % var.upper()
        setattr(self, name, QtWidgets.QDateTimeEdit(parent))
        time_obj: QtWidgets.QDateTimeEdit = getattr(self, name)
        time_obj.setLocale(QLocale(QLocale.Chinese, QLocale.China))
        time_obj.setCalendarPopup(True)
        time_obj.setDisplayFormat('yyyy/M/d h:mm')
        time_obj.setDateTime(QDateTime.currentDateTime())
        time_obj.setFixedSize(160, 35)
        return time_obj

    def QPeriodBand(self, var, text, parent):
        splitter_name = 'splitter_time_%s' % var.lower()
        setattr(self, splitter_name, QtWidgets.QSplitter(parent))
        splitter_obj: QtWidgets.QSplitter = getattr(self, splitter_name)
        splitter_obj.setHandleWidth(3)
        splitter_obj.setChildrenCollapsible(False)

        radio_name = '%s_TIME' % var.upper()
        setattr(self, radio_name, QtWidgets.QRadioButton(text, parent))
        radio_obj: QtWidgets.QRadioButton = getattr(self, radio_name)

        splitter_obj.addWidget(radio_obj)
        splitter_obj.addWidget(QtWidgets.QLabel('从', parent))
        splitter_obj.addWidget(self.QDateTimePack('%s_time_begin' % var, parent))
        splitter_obj.addWidget(QtWidgets.QLabel('到', parent))
        splitter_obj.addWidget(self.QDateTimePack('%s_time_end' % var, parent))
        splitter_obj.setStretchFactor(0, 1)

        return radio_obj, splitter_obj

    def QScrollAreaPack(self, var, parent):
        scroll_name = 'scroll_%s' % var
        setattr(self, scroll_name, QtWidgets.QScrollArea(parent))
        scroll_obj: QtWidgets.QScrollArea = getattr(self, scroll_name)
        scroll_obj.setWidgetResizable(True)
        scroll_obj.setFrameShape(QFrame.NoFrame)
        textEdit_send_sbar = QtWidgets.QScrollBar()
        textEdit_send_sbar.setStyleSheet("""
             QScrollBar:vertical {
                  border-width: 0px;
                  border: none;
                  background:rgba(64, 65, 79, 0);
                  width:12px;
                  margin: 0px 0px 0px 0px;
              }
              QScrollBar::handle:vertical {
                  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                  stop: 0 #6CA6CD, stop: 0.5 #6CA6CD, stop:1 #6CA6CD);
                  height: 50px;
                  margin: 0 0px 0 0px;
                  border-radius: 6px;
              }
              QScrollBar::add-line:vertical {
                  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                  stop: 0 rgba(64, 65, 79, 0), stop: 0.5 rgba(64, 65, 79, 0),  stop:1 rgba(64, 65, 79, 0));
                  height: 0px;
                  border: none;
                  subcontrol-position: bottom;
                  subcontrol-origin: margin;
              }
              QScrollBar::sub-line:vertical {
                  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
                  stop: 0  rgba(64, 65, 79, 0), stop: 0.5 rgba(64, 65, 79, 0),  stop:1 rgba(64, 65, 79, 0));
                  height: 0 px;
                  border: none;
                  subcontrol-position: top;
                  subcontrol-origin: margin;
              }
              
              """)
        scroll_obj.setVerticalScrollBar(textEdit_send_sbar)

        scroll_content_name = 'scroll_content_%s' % var
        setattr(self, scroll_content_name, QtWidgets.QWidget())
        scroll_content_obj: QtWidgets.QWidget = getattr(self, scroll_content_name)

        grid_scroll_name = 'grid_scroll_%s' % var
        setattr(self, grid_scroll_name, QtWidgets.QGridLayout(self.__dict__[scroll_content_name]))
        grid_scroll_obj: QtWidgets.QGridLayout = getattr(self, grid_scroll_name)
        scroll_obj.setWidget(scroll_content_obj)

        return scroll_obj, scroll_content_obj, grid_scroll_obj

    def QDuet(self, *args, **kwargs):
        args = list(args)
        parent, grid, duet, var = args.pop(0), args.pop(0), args.pop(0), args.pop(0)
        var = var.lower()

        splitter_obj = self.QSplitterPack('%s' % var, parent)
        right_name, right_obj = var.upper(), None
        if QtWidgets.QLabel in duet:
            left_name = 'label_%s' % var
            setattr(self, left_name, QtWidgets.QLabel(parent))
            left_obj: QtWidgets.QLabel = getattr(self, left_name)
            text = kwargs.get('text', None) if not args else args.pop(0)
            if text == None:
                text = var.upper().replace('UI_KEY_', '')
            left_obj.setText(text)

        if duet == (QtWidgets.QLabel, QtWidgets.QSpinBox):
            scope = kwargs.get('scope', None) if not args else args.pop(0)
            if isinstance(scope[0], int):
                setattr(self, right_name, QtWidgets.QSpinBox(parent))
                right_obj: QtWidgets.QSpinBox = getattr(self, right_name)
            else:
                setattr(self, right_name, QtWidgets.QDoubleSpinBox(parent))
                right_obj: QtWidgets.QDoubleSpinBox = getattr(self, right_name)
            right_obj.setMinimum(scope[0])
            right_obj.setMaximum(scope[1])
            right_obj.setSingleStep(0.01)

        elif duet == (QtWidgets.QLabel, QtWidgets.QLineEdit):
            placeholder = kwargs.get('placeholder', '') if not args else args.pop(0)
            validator = kwargs.get('validator', None) if not args else args.pop(0)
            setattr(self, right_name, QtWidgets.QLineEdit(parent))
            right_obj: QtWidgets.QLineEdit = getattr(self, right_name)
            right_obj.setPlaceholderText(placeholder)
            right_obj.setValidator(validator) if validator else None
            right_obj.setStyleSheet("border-radius: 5px;"  # 设置边框圆角
                                    "border-width: 2px;"
                                    "border-color: rgb(108, 166, 205);"
                                    "border-style: outset;")
            font = QFont()
            font.setPointSize(12)
            right_obj.setFont(font)
            # left_obj.setFixedWidth(110)

        elif duet == (QtWidgets.QLabel, QtWidgets.QComboBox):
            items = kwargs.get('items', []) if not args else args.pop(0)
            setattr(self, right_name, QtWidgets.QComboBox(parent))
            right_obj: QtWidgets.QComboBox = getattr(self, right_name)
            right_obj.addItems(items)

        elif duet == (QtWidgets.QLabel, QtWidgets.QPushButton):
            text = kwargs['text'] if not args else args.pop(0)
            setattr(self, right_name, QtWidgets.QPushButton(parent))
            right_obj: QtWidgets.QPushButton = getattr(self, right_name)
            right_obj.setText(text)
            right_obj.setFixedHeight(50)

        elif duet == (QtWidgets.QLabel, QtWidgets.QLabel):
            text = kwargs.get('text', '') if not args else args.pop(0)
            setattr(self, right_name, QtWidgets.QLabel(parent))
            right_obj: QtWidgets.QLabel = getattr(self, right_name)
            right_obj.setText(text)
            right_obj.setFixedHeight(50)

        elif duet == (QtWidgets.QLabel, QtWidgets.QCheckBox):
            setattr(self, right_name, QtWidgets.QCheckBox('启用', parent))
            right_obj: QtWidgets.QCheckBox = getattr(self, right_name)

        elif duet == (QtWidgets.QLabel, QSwitch):
            indicatorSize = kwargs.get('indicatorSize', (60, 60)) if not args else args.pop(0)
            checked = kwargs.get('checked', False) if not args else args.pop(0)
            setattr(self, right_name, QSwitch(parent, indicatorSize, checked))
            right_obj: QSwitch = getattr(self, right_name)

        elif duet == (QtWidgets.QCheckBox, QtWidgets.QLineEdit):
            text = kwargs['text'] if not args else args.pop(0)
            left_name = '%s_SWITCH_REBOOT' % (var.upper().replace('_REBOOT', ''))
            setattr(self, left_name, QtWidgets.QCheckBox(text, parent))
            left_obj: QtWidgets.QCheckBox = getattr(self, left_name)
            setattr(self, right_name, QtWidgets.QLineEdit(parent))
            right_obj: QtWidgets.QLineEdit = getattr(self, right_name)
            right_obj.setFixedSize(150, 35)
            right_obj.setEnabled(False)
            left_obj.toggled.connect(right_obj.setEnabled)

        else:
            print('Error: Unknown Band', duet)
            return

        right_obj.setFixedSize(130, 35)
        splitter_obj.addWidget(left_obj)
        splitter_obj.addWidget(right_obj)
        grid.addWidget(splitter_obj)

        if 'line' in kwargs and kwargs['line'] or (args and args[-1] == 'line'):
            self.QDivider(parent, grid)

        return left_obj, right_obj, splitter_obj

    def QTabPro(self, parent, grid, var, items):
        setattr(self, var, QtWidgets.QTabWidget(parent))
        tab_obj: QtWidgets.QTabWidget = getattr(self, var)
        for sub_var, sub_txt, sub_content in items:
            widget_name = 'tab_%s' % sub_var.lower()
            setattr(self, widget_name, QWidget())
            widget_obj: QWidget = getattr(self, widget_name)
            grid_sub_name = 'grid_%s' % sub_var.lower()
            setattr(self, grid_sub_name, QtWidgets.QGridLayout(widget_obj))
            grid_sub_obj = getattr(self, grid_sub_name)
            list_name = 'TAB_%s_LIST' % sub_var.upper()
            setattr(self, list_name, QtWidgets.QListWidget(widget_obj))
            list_obj: QtWidgets.QListWidget = getattr(self, list_name)
            list_obj.addItems(sub_content)
            for i in range(len(sub_content)):
                item = list_obj.item(i)
                item.setCheckState(Qt.Checked)
                item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            grid_sub_obj.addWidget(list_obj)
            tab_obj.addTab(widget_obj, sub_txt)
        grid.addWidget(tab_obj)

    @staticmethod
    def QDivider(parent, grid=None, shape='h', color='darkgray'):
        """ 分割线 """
        shape = shape.lower()
        line = QFrame(parent)
        if shape == 'h':
            line.setFrameShape(QFrame.HLine)
        elif shape == 'v':
            line.setFrameShape(QFrame.VLine)
        line.setStyleSheet('color: %s' % color)
        grid.addWidget(line) if grid else None
        return line

    @staticmethod
    def QMessagePro(title, text, items=[], font_size=15, follow=False):
        font = QFont()
        font.setBold(True)
        font.setPointSize(font_size)
        msg = MessagePro()
        msg.setFont(font)
        msg.setWindowTitle(title)
        if text: msg.setText(text)
        if follow: msg.move(QCursor.pos().x() - 60, QCursor.pos().y() - 30)
        msg.addButtons(items)
        return msg.exec_()

    @staticmethod
    def QTimedPopover(parent, types, title, text, delay, Yes=True, No=False, default='Yes'):
        """ 定时弹窗 """
        Yes = QtWidgets.QPushButton('Yes') if Yes == True else Yes
        msg = QtWidgets.QMessageBox(parent)
        msg.setIcon(types)
        msg.setWindowTitle(title)
        msg.setText(text)
        msg.addButton(Yes, QtWidgets.QMessageBox.YesRole)
        if No:
            msg.addButton(No, QtWidgets.QMessageBox.NoRole)
        if default == 'Yes':
            Yes.animateClick(delay * 1000)
        elif default == 'No':
            No.animateClick(delay * 1000)
        msg.exec_()
        return msg.clickedButton()

    @staticmethod
    def SetColorText(obj, text, color):
        text = '<span style="color: %s">%s</span>' % (color, text)
        obj.setText(text)

    @staticmethod
    def GetValue(obj):
        if isinstance(obj, (QtWidgets.QSpinBox, QtWidgets.QDoubleSpinBox)):
            return obj.value()
        elif isinstance(obj, (QtWidgets.QLabel, QtWidgets.QLineEdit, QtWidgets.QPushButton)):
            return obj.text()
        elif isinstance(obj, QtWidgets.QComboBox):
            return obj.currentText()
        elif isinstance(obj, (QtWidgets.QRadioButton, QtWidgets.QCheckBox)):
            return obj.isChecked()
        elif isinstance(obj, QtWidgets.QDateTimeEdit):
            return obj.dateTime().toTime_t()
        else:
            print('Error:', '无法识别此控件类型')

    @staticmethod
    def SetValue(obj, v):
        if isinstance(obj, (QtWidgets.QSpinBox, QtWidgets.QDoubleSpinBox)):
            return obj.setValue(v)
        elif isinstance(obj, (QtWidgets.QLabel, QtWidgets.QLineEdit, QtWidgets.QPushButton)):
            return obj.setText(str(v))
        elif isinstance(obj, QtWidgets.QComboBox):
            return obj.setCurrentText(str(v))
        elif isinstance(obj, (QtWidgets.QRadioButton, QtWidgets.QCheckBox)):
            return obj.setChecked(v)
        elif isinstance(obj, QtWidgets.QDateTimeEdit):
            return obj.setDateTime(QDateTime.fromTime_t(v))
        else:
            print('Error:', '无法识别此控件类型')

    def _initUI(self):
        """ BeOverridden """
        pass

    def _connect(self):
        """ BeOverridden """
        pass

    def _dockContent(self, var, content_obj, grid_obj):
        """ BeOverridden """
        pass


class MessagePro(QDialog):
    def __init__(self, parent=None):
        super(MessagePro, self).__init__(parent)
        self.initUI()

    def closeEvent(self, event): self.done(1024)

    def initUI(self):
        self.grid = QtWidgets.QGridLayout(self)
        QShortcut('Esc', self).activated.connect(self.close)

    def setText(self, text: str):
        self.content = QtWidgets.QLabel(text, self)
        self.grid.addWidget(self.content, 0, 0)

    def addButtons(self, items: list):
        self.splitter = QtWidgets.QSplitter(self)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.setHandleWidth(3)
        for i, item in enumerate(items):
            btn = QtWidgets.QPushButton(item, self)
            btn.clicked.connect(lambda state, v=i: self.done(v))
            self.splitter.addWidget(btn)
        self.grid.addWidget(self.splitter, 1, 0)


class MyHighlighter(QSyntaxHighlighter):
    """ 自定义文本框语法高亮 """

    def highlightBlock(self, text):
        myClassFormat = QTextCharFormat()
        myClassFormat.setFontWeight(QFont.Bold)

        keyword_map = {
            ' ERROR ': 'darkRed',
            ' DEBUG ': 'darkMagenta',
            ' INFO ': 'darkBlue',
            ' WARNING ': 'darkYellow'
        }
        for keyword, color in keyword_map.items():
            myClassFormat.setForeground(getattr(Qt, color))

            pos = 0
            expression = QRegExp(keyword)
            index = expression.indexIn(text, pos)
            while index != -1:
                length = expression.matchedLength()
                self.setFormat(index, length, myClassFormat)
                pos = index + length
                index = expression.indexIn(text, pos)
